﻿using System.Xml.Linq;
using Phoenix.Xna.Framework.Serialization.Markup;
using Phoenix.Xna.Framework.Serialization.Markup.Objects;

namespace Phoenix.Xna.Framework.Serialization
{
    public class Serializer : ISerializer
    {
        /// <summary>
        /// Gets this serializer's MarkupSelector.
        /// </summary>
        internal MarkupSelector MarkupSelector { get; private set; }

        /// <summary>
        /// Gets this serializer's ReferenceManager.
        /// </summary>
        internal ReferenceManager ReferenceManager { get; private set; }
        
        /// <summary>
        /// Initializes a new instance of the SerializationService class.
        /// </summary>
        public Serializer()
        {
            MarkupSelector = new MarkupSelector();
            MarkupSelector.Serializer = this;
            ReferenceManager = new ReferenceManager();            
        }

        /// <summary>
        /// Creates a xml model of the instance and all of it's decendents based on the SerializableCollectionAttribute & the DefaultValueAttribute.
        /// </summary>
        /// <param name="instance">The object model to be serialized.</param>
        /// <returns>The string serialized form of the object model.</returns>
        public string Serialize(object instance)
        {
            ReferenceManager.Clear();
            IMarkupObject markupObject = MarkupSelector.GetMarkupObjectFor(instance);
            XElement xmlObject = markupObject.Serialize() as XElement;
            return xmlObject.ToString();
        }

        /// <summary>
        /// Creates a xml model of the instance and all of it's decendents based on the SerializableCollectionAttribute & the DefaultValueAttribute.
        /// </summary>
        /// <param name="instance">The object model to be serialized.</param>
        /// <returns>The XElement serialized form of the object model.</returns>
        public XElement SerializeAsXElement(object instance)
        {
            return XElement.Parse(Serialize(instance));
        }

        /// <summary>
        /// Creates a fully instantiated object model defined by the the xml model.
        /// </summary>
        /// <param name="xml">The persisted xml model</param>
        /// <returns>The fully instantiated object model</returns>
        public object Deserialize(string xml)
        {
            return Deserialize(XElement.Parse(xml));
        }

        public T Deserialize<T>(string xml)
        {
            return (T)Deserialize(xml);
        }

        /// <summary>
        /// Creates a fully instantiated object model defined by the the xml model.
        /// </summary>
        /// <param name="xml">The persisted xml model</param>
        /// <returns>The fully instantiated object model</returns>
        public object Deserialize(XElement element)
        {
            ReferenceManager.Clear();
            IMarkupObject markupObject = MarkupSelector.GetMarkupObjectFor(element);
            markupObject.Deserialize(element);
            markupObject.ConstructInstance();
            return markupObject.Instance;
        }

        public T Deserialize<T>(XElement element)
        {
            return (T)Deserialize(element);
        }
    }
}
